/* eslint-disable */
/**
* vkBeautify - javascript plugin to pretty-print or minify text in XML, JSON, CSS and SQL formats.
*
* Copyright (c) 2012 Vadim Kiryukhin
* vkiryukhin @ gmail.com
* http://www.eslinstructor.net/vkbeautify/
*
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*
*   Pretty print
*
*        vkbeautify.xml(text [,indent_pattern]);
*        vkbeautify.json(text [,indent_pattern]);
*        vkbeautify.css(text [,indent_pattern]);
*        vkbeautify.sql(text [,indent_pattern]);
*
*        @text - String; text to beatufy;
*        @indent_pattern - Integer | String;
*                Integer:  number of white spaces;
*                String:   character string to visualize indentation ( can also be a set of white spaces )
*   Minify
*
*        vkbeautify.xmlmin(text [,preserve_comments]);
*        vkbeautify.jsonmin(text);
*        vkbeautify.cssmin(text [,preserve_comments]);
*        vkbeautify.sqlmin(text);
*
*        @text - String; text to minify;
*        @preserve_comments - Bool; [optional];
*                Set this flag to true to prevent removing comments from @text ( minxml and mincss functions only. )
*
*   Examples:
*        vkbeautify.xml(text); // pretty print XML
*        vkbeautify.json(text, 4 ); // pretty print JSON
*        vkbeautify.css(text, '. . . .'); // pretty print CSS
*        vkbeautify.sql(text, '----'); // pretty print SQL
*
*        vkbeautify.xmlmin(text, true);// minify XML, preserve comments
*        vkbeautify.jsonmin(text);// minify JSON
*        vkbeautify.cssmin(text);// minify CSS, remove comments ( default )
*        vkbeautify.sqlmin(text);// minify SQL
*
*/
function createShiftArr (step) {
  var space = '    '

  if (isNaN(parseInt(step))) { // argument is string
    space = step
  } else { // argument is integer
    switch (step) {
      case 1: space = ' '; break
      case 2: space = '  '; break
      case 3: space = '   '; break
      case 4: space = '    '; break
      case 5: space = '     '; break
      case 6: space = '      '; break
      case 7: space = '       '; break
      case 8: space = '        '; break
      case 9: space = '         '; break
      case 10: space = '          '; break
      case 11: space = '           '; break
      case 12: space = '            '; break
    }
  }

  var shift = ['\n'] // array of shifts
  for (var ix = 0; ix < 100; ix++) {
    shift.push(shift[ix] + space)
  }
  return shift
}

function vkbeautify () {
  this.step = '    ' // 4 spaces
  this.shift = createShiftArr(this.step)
};

vkbeautify.prototype.xml = function (text, step) {
  var ar = text.replace(/>\s{0,}</g, '><')
				 .replace(/</g, '~::~<')
				 .replace(/\s*xmlns\:/g, '~::~xmlns:')
				 .replace(/\s*xmlns\=/g, '~::~xmlns=')
				 .split('~::~')
  var len = ar.length
  var inComment = false
  var deep = 0
  var str = ''
  var ix = 0
  var shift = step ? createShiftArr(step) : this.shift

  for (ix = 0; ix < len; ix++) {
    // start comment or <![CDATA[...]]> or <!DOCTYPE //
    if (ar[ix].search(/<!/) > -1) {
      str += shift[deep] + ar[ix]
      inComment = true
      // end comment  or <![CDATA[...]]> //
      if (ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1 || ar[ix].search(/!DOCTYPE/) > -1) {
        inComment = false
      }
    } else
    // end comment  or <![CDATA[...]]> //
    if (ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1) {
      str += ar[ix]
      inComment = false
    } else
    // <elm></elm> //
    if (/^<\w/.exec(ar[ix - 1]) && /^<\/\w/.exec(ar[ix]) &&
				/^<[\w:\-\.\,]+/.exec(ar[ix - 1]) == /^<\/[\w:\-\.\,]+/.exec(ar[ix])[0].replace('/', '')) {
      str += ar[ix]
      if (!inComment) deep--
    } else
			 // <elm> //
    if (ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) == -1 && ar[ix].search(/\/>/) == -1) {
      str = !inComment ? str += shift[deep++] + ar[ix] : str += ar[ix]
    } else
			 // <elm>...</elm> //
    if (ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) > -1) {
      str = !inComment ? str += shift[deep] + ar[ix] : str += ar[ix]
    } else
    // </elm> //
    if (ar[ix].search(/<\//) > -1) {
      str = !inComment ? str += shift[--deep] + ar[ix] : str += ar[ix]
    } else
    // <elm/> //
    if (ar[ix].search(/\/>/) > -1) {
      str = !inComment ? str += shift[deep] + ar[ix] : str += ar[ix]
    } else
    // <? xml ... ?> //
    if (ar[ix].search(/<\?/) > -1) {
      str += shift[deep] + ar[ix]
    } else
    // xmlns //
    if (ar[ix].search(/xmlns\:/) > -1 || ar[ix].search(/xmlns\=/) > -1) {
      str += shift[deep] + ar[ix]
    } else {
      str += ar[ix]
    }
  }

  return (str[0] == '\n') ? str.slice(1) : str
}

vkbeautify.prototype.json = function (text, step) {
  var step = step || this.step

  if (typeof JSON === 'undefined') return text

  if (typeof text === 'string') return JSON.stringify(JSON.parse(text), null, step)
  if (typeof text === 'object') return JSON.stringify(text, null, step)

  return text // text is not string nor object
}

vkbeautify.prototype.css = function (text, step) {
  var ar = text.replace(/\s{1,}/g, ' ')
    .replace(/\{/g, '{~::~')
    .replace(/\}/g, '~::~}~::~')
    .replace(/\;/g, ';~::~')
    .replace(/\/\*/g, '~::~/*')
    .replace(/\*\//g, '*/~::~')
    .replace(/~::~\s{0,}~::~/g, '~::~')
    .split('~::~')
  var len = ar.length
  var deep = 0
  var str = ''
  var ix = 0
  var shift = step ? createShiftArr(step) : this.shift

  for (ix = 0; ix < len; ix++) {
    if (/\{/.exec(ar[ix])) {
      str += shift[deep++] + ar[ix]
    } else
    if (/\}/.exec(ar[ix])) {
      str += shift[--deep] + ar[ix]
    } else
    if (/\*\\/.exec(ar[ix])) {
      str += shift[deep] + ar[ix]
    } else {
      str += shift[deep] + ar[ix]
    }
  }
  return str.replace(/^\n{1,}/, '')
}

// ----------------------------------------------------------------------------

function isSubquery (str, parenthesisLevel) {
  return parenthesisLevel - (str.replace(/\(/g, '').length - str.replace(/\)/g, '').length)
}

function split_sql (str, tab) {
  return str.replace(/\s{1,}/g, ' ')

    .replace(/ AND /ig, '~::~' + tab + tab + 'AND ')
    .replace(/ BETWEEN /ig, '~::~' + tab + 'BETWEEN ')
    .replace(/ CASE /ig, '~::~' + tab + 'CASE ')
    .replace(/ ELSE /ig, '~::~' + tab + 'ELSE ')
    .replace(/ END /ig, '~::~' + tab + 'END ')
    .replace(/ FROM /ig, '~::~FROM ')
    .replace(/ GROUP\s{1,}BY/ig, '~::~GROUP BY ')
    .replace(/ HAVING /ig, '~::~HAVING ')
  // .replace(/ SET /ig," SET~::~")
    .replace(/ IN /ig, ' IN ')

    .replace(/ JOIN /ig, '~::~JOIN ')
    .replace(/ CROSS~::~{1,}JOIN /ig, '~::~CROSS JOIN ')
    .replace(/ INNER~::~{1,}JOIN /ig, '~::~INNER JOIN ')
    .replace(/ LEFT~::~{1,}JOIN /ig, '~::~LEFT JOIN ')
    .replace(/ RIGHT~::~{1,}JOIN /ig, '~::~RIGHT JOIN ')

    .replace(/ ON /ig, '~::~' + tab + 'ON ')
    .replace(/ OR /ig, '~::~' + tab + tab + 'OR ')
    .replace(/ ORDER\s{1,}BY/ig, '~::~ORDER BY ')
    .replace(/ OVER /ig, '~::~' + tab + 'OVER ')

    .replace(/\(\s{0,}SELECT /ig, '~::~(SELECT ')
    .replace(/\)\s{0,}SELECT /ig, ')~::~SELECT ')

    .replace(/ THEN /ig, ' THEN~::~' + tab + '')
    .replace(/ UNION /ig, '~::~UNION~::~')
    .replace(/ USING /ig, '~::~USING ')
    .replace(/ WHEN /ig, '~::~' + tab + 'WHEN ')
    .replace(/ WHERE /ig, '~::~WHERE ')
    .replace(/ WITH /ig, '~::~WITH ')

  // .replace(/\,\s{0,}\(/ig,",~::~( ")
  // .replace(/\,/ig,",~::~"+tab+tab+"")

    .replace(/ ALL /ig, ' ALL ')
    .replace(/ AS /ig, ' AS ')
    .replace(/ ASC /ig, ' ASC ')
    .replace(/ DESC /ig, ' DESC ')
    .replace(/ DISTINCT /ig, ' DISTINCT ')
    .replace(/ EXISTS /ig, ' EXISTS ')
    .replace(/ NOT /ig, ' NOT ')
    .replace(/ NULL /ig, ' NULL ')
    .replace(/ LIKE /ig, ' LIKE ')
    .replace(/\s{0,}SELECT /ig, 'SELECT ')
    .replace(/\s{0,}UPDATE /ig, 'UPDATE ')
    .replace(/ SET /ig, ' SET ')

    .replace(/~::~{1,}/g, '~::~')
    .split('~::~')
}

vkbeautify.prototype.sql = function (text, step) {
  var ar_by_quote = text.replace(/\s{1,}/g, ' ')
    .replace(/\'/ig, "~::~\'")
    .split('~::~')
  var len = ar_by_quote.length
  var ar = []
  var deep = 0
  var tab = this.step; var // +this.step,
    inComment = true
  var inQuote = false
  var parenthesisLevel = 0
  var str = ''
  var ix = 0
  var shift = step ? createShiftArr(step) : this.shift

  for (ix = 0; ix < len; ix++) {
    if (ix % 2) {
      ar = ar.concat(ar_by_quote[ix])
    } else {
      ar = ar.concat(split_sql(ar_by_quote[ix], tab))
    }
  }

  len = ar.length
  for (ix = 0; ix < len; ix++) {
    parenthesisLevel = isSubquery(ar[ix], parenthesisLevel)

    if (/\s{0,}\s{0,}SELECT\s{0,}/.exec(ar[ix])) {
      ar[ix] = ar[ix].replace(/\,/g, ',\n' + tab + tab + '')
    }

    if (/\s{0,}\s{0,}SET\s{0,}/.exec(ar[ix])) {
      ar[ix] = ar[ix].replace(/\,/g, ',\n' + tab + tab + '')
    }

    if (/\s{0,}\(\s{0,}SELECT\s{0,}/.exec(ar[ix])) {
      deep++
      str += shift[deep] + ar[ix]
    } else
    if (/\'/.exec(ar[ix])) {
      if (parenthesisLevel < 1 && deep) {
        deep--
      }
      str += ar[ix]
    } else {
      str += shift[deep] + ar[ix]
      if (parenthesisLevel < 1 && deep) {
        deep--
      }
    }
    var junk = 0
  }

  str = str.replace(/^\n{1,}/, '').replace(/\n{1,}/g, '\n')
  return str
}

vkbeautify.prototype.xmlmin = function (text, preserveComments) {
  var str = preserveComments ? text
							   : text.replace(/\<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)\>/g, '')
									 .replace(/[ \r\n\t]{1,}xmlns/g, ' xmlns')
  return str.replace(/>\s{0,}</g, '><')
}

vkbeautify.prototype.jsonmin = function (text) {
  if (typeof JSON === 'undefined') return text

  return JSON.stringify(JSON.parse(text), null, 0)
}

vkbeautify.prototype.cssmin = function (text, preserveComments) {
  var str = preserveComments ? text
							   : text.replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\//g, '')

  return str.replace(/\s{1,}/g, ' ')
			  .replace(/\{\s{1,}/g, '{')
			  .replace(/\}\s{1,}/g, '}')
			  .replace(/\;\s{1,}/g, ';')
			  .replace(/\/\*\s{1,}/g, '/*')
			  .replace(/\*\/\s{1,}/g, '*/')
}

vkbeautify.prototype.sqlmin = function (text) {
  return text.replace(/\s{1,}/g, ' ').replace(/\s{1,}\(/, '(').replace(/\s{1,}\)/, ')')
}

module.exports = new vkbeautify()
